/*********************************************
 Filename: Linkedl2b.c 
 Purpose:  Based on the quene code, PCB was added as the 
 element of the listNode struct. 
 Date: October 4, 2008 
 Modifications: 
 1. char *data changed to PCB *data
 2. since 5 states have been predefined,it should be a int type 
    quene_id. The name of the PCB and the state of PCB are used 
    as the identifier in all functions. 

**********************************************/ 

#include <stdio.h>
#include <stdlib.h>
#include "PCB.c" 
#include "mpx_supt.c" 

#define SIZE 20

struct listNode
{
	PCB *data;
	struct listNode *nextPtr;
};

typedef struct listNode ListNode;
typedef ListNode *ListNodePtr;

struct list{
	ListNodePtr head;
      
};

typedef struct list List;
typedef List *ListPtr;

ListPtr RunningQueue;
ListPtr ReadyQueue;
ListPtr BlockQueue;
ListPtr SusReadyQueue;
ListPtr SusBlockQueue;

void queue_init(void);

ListNodePtr find_pcb(ListPtr sPtr, char *value);
ListNodePtr findall_pcb(char *value);
void set_priority(char *value, int pri);

void show(int quene_id);
void insertpcb(char *data_name, int quene_id);
void removepcb(char *data_name, int quene_id);
void insert(ListPtr sPtr, char *data_name);
PCB* delete(ListPtr sPtr, char *data_name);
int isEmpty(ListPtr sPtr);
void printList(ListPtr currPtr);

void queue_init(void){
ReadyQueue = sys_alloc_mem(sizeof(List));
ReadyQueue->head=NULL;

RunningQueue = sys_alloc_mem(sizeof(List));
RunningQueue->head=NULL;

BlockQueue = sys_alloc_mem(sizeof(List));
BlockQueue->head=NULL;

SusReadyQueue = sys_alloc_mem(sizeof(List));
SusReadyQueue->head=NULL;

SusBlockQueue = sys_alloc_mem(sizeof(List));
SusBlockQueue->head=NULL;
}

/***************************************************** 
Purpose: Find pcb with the name as value from a certain quene 
Precondition:  quene_init() has been convoked. 
*****************************************************/ 
ListNodePtr find_pcb(ListPtr sPtr, char *value){
  
  ListNodePtr currPtr;
  if (!isEmpty(ListPtr sPtr)) 
 {
    currPtr = sPtr->head; 
    while (currPtr!=NULL)
     {
    if (!strcmp(currPtr->data->pcb_name, value))
     return currPtr; 
    else
     currPtr=currPtr->nextPtr; 
    }
  
  }
  else 
  return  NULL; 
}

/* Find the pcb in al 5 quenes */ 
ListNodePtr findall_pcb(char *value) {
  ListNodePtr tPCB; 
  
 if ((tPCB = find_pcb(RunningQuene, value))!=NULL)
 return tPCB;
  elseif ((tPCB = find_pcb(ReadyQuene, value))!=NULL)
  return tPCB; 
    elseif ((tPCB = find_pcb(BlockQuene, value))!=NULL)
    return tPCB; 
      elseif ((tPCB = find_pcb(SusReadyQuene, value))!=NULL)
      return tPCB; 
        else
          return (tPCB = find_pcb(SusBlockQuene, value));
  
}

void set_priority(char *value, int pri){
// make sure PCB with the name of value exists
 PCB*  sPCB;
 if (findall_pcb(value)!=NULL)
 {
  sPCB = findall_pcb(value)->data;
  strcpy(sPCB->pcb_priority,pri); 

 }
 else
 {
  printf( " This PCB does not exist."); 
 }


}

void insertpcb(PCB* data, int quene_id){

	if(quene_id==1000){
	   fifo_insert(RunningQueue, data);
	}
	else if(quene_id==2000){
	   fifo_insert(ReadyQueue, data);
	}
	else if(quene_id==3000){
	   fido_insert(BlockQueue, data);
	}
	else if(quene_id==4000){
	   fifo_insert(SusReadyQueue, data);
	}
	else if(quene_id==5000){
	   fifo_insert(SusBlockQueue, data);
	}
	else{
	   printf("Invalid process state!\n");
	   return;
	}
}

void removepcb(char *data_name, char *queue){
	if(quene_id==2000){
	   if(!isEmpty(ReadyQueue)){
	      if(delete(ReadyQueue, data)){
		 printf("%s deleted.\n", data);
		 }
	      else
		 printf("%s not found.\n", data);
	      }
	      else if(isEmpty(ReadyQueue)){
		 printf("List is empty.\n");
		 return;
	      }
	}
	else if(quene_id==1000){
	   if(!isEmpty(RunningQueue)){
	      if(delete(RunningQueue, data)){
		 printf("%s deleted.\n", data);
		 }
	      else
		 printf("%s not found.\n", data);
	      }
	      else if(isEmpty(RunningQueue)){
		 printf("List is empty.\n");
		 return;
	      }
	}
	else if(quene_id==3000){
	   if(!isEmpty(BlockQueue)){
	      if(delete(BlockQueue, data)){
		 printf("%s deleted.\n", data);
		 }
	      else
		 printf("%s not found.\n", data);
	      }
	      else if(isEmpty(BlockQueue)){
		 printf("List is empty.\n");
		 return;
	      }
	}
	else if(quene_id==4000){
	   if(!isEmpty(SusReadyQueue)){
	      if(delete(SusReadyQueue, data)){
		 printf("%s deleted.\n", data);
		 }
	      else
		 printf("%s not found.\n", data);
	      }
	      else if(isEmpty(SusReadyQueue)){
		 printf("List is empty.\n");
		 return;
	      }
	}
	else if(quene_id==5000){
	   if(!isEmpty(SusBlockQueue)){
	      if(delete(SusBlockQueue, data)){
		 printf("%s deleted.\n", data);
		 }
	      else
		 printf("%s not found.\n", data);
	      }
	      else if(isEmpty(SusBlockQueue)){
		 printf("List is empty.\n");
		 return;
	      }
	}
	else{
	   printf("Invalid process state!\n");
	   return;
	}
}
void show (int quene_id){
	if(quene_id==2000){
	   printf ("Printing Ready Queue:\n");
	   printList(ReadyQueue);
	}
	else if(quene_id==1000){
	   printList(RunningQueue);
	}
	else if(quene_id==3000){
	   printList(BlockQueue);
	}
	else if(quene_id==4000){
	   printList(SusReadyQueue);
	}
	else if(quene_id==5000){
	   printList(SusBlockQueue);
	}
	else{
	   printf("Invalid process state!\n");
	   return;
	}
}

/* Add the PCB to the end of a certain quene */ 
void fifo_insert(ListPtr sPtr, PCB *value) {
	ListNodePtr newPtr;
	ListNodePtr prevPtr;
	ListNodePtr currPtr;

	newPtr = sys_alloc_mem(sizeof(ListNode));
	newPtr->nextPtr=NULL;
	newPtr->data = value;
      
      currPtr = sPtr->head;
      if (isEmpty(sPtr))
       {
       sPtr->head= newPtr;
       return;
       }
      
      while( currPtr!=NULL)
       {
       prevPtr =currPtr;
       currPtr= currPtr->nextPtr; 
       }
       
       currPtr = newPtr;
}
       


/**************************************
 Delete the PCB with the specified name frome the quene 
 This PCB can be anywhere in the quene identified by its name. 
**************************************************************/ 
 

PCB* delete(ListPtr sPtr, char *data_name){
  ListNodePtr currPtr;
  ListNodePtr tempPtr; 

  if (!isEmpty(ListPtr sPtr)) 
 {
    currPtr = sPtr->head; 
    while (currPtr!=NULL)
     {
      
     if (strcmp(currPtr->data->pcb_name, value))
       {
      prePtr=currPtr;
      currPtr=currPtr->nextPtr; 
       }
      else
       {
      return currPtr->data; 
       }
     }
   
  }
  else 
  return  NULL;
}





int isEmpty(ListPtr sPtr)
{
	return (sPtr->head == NULL);
}


void printList(ListPtr currPtr)
{
	ListNodePtr next;

	if(currPtr->head == NULL)
	{
		printf("List is empty.\n");
	}
	else
	{
		printf("The list is: \n");
		next = currPtr->head;

		while(next != NULL)
		{
			printf("%12s  ", next -> data->pcb_name);
                  printf("%4d  ", next -> data->pcb_class);
                  printf("%6d  ", next -> data->pcb_state);
                  printf("%4d  ", next -> data->pcb_priority);

			next = next->nextPtr;
		}
		printf("NULL\n");
	}
}
